﻿using System;
using SoftwareConsulting.BI11.NumericalMethods.Interfaces;

namespace SoftwareConsulting.BI11.NumericalMethods.Optimization
{
    /// <summary>
    /// Класс общего оптимизатора многопеременных функций
    /// </summary>
    public class MultiVariableGeneralOptimizer : MultiVariableOptimizer
    {
	    private double[] _initialRange;//стартовый диапазон для случайного поиска

        /// <summary>
        /// Конструктор класса
        /// </summary>
        /// <param name="function">Функция, требующая решения</param>
        /// <param name="pointsCreator">Фабрика точек</param>
        /// <param name="initialValue">Начальное значение</param>
        public MultiVariableGeneralOptimizer(IManyVariableFunction function, SuspiciousOptimalPointAndVectorFactory pointsCreator, double[] initialValue)
                : base(function, pointsCreator, initialValue)
        {
        }

        /// <summary>
        /// Выполняет итерацию
        /// </summary>
        /// <returns></returns>
        public override double DoIteration()
        {
            HillClimbingPowellAlgorithm hillClimbing = new HillClimbingPowellAlgorithm(Function, PointsFactory, GetResult());
            hillClimbing.SetDesiredPrecision(DesiredPrecision);
            hillClimbing.SetMaximumIterationsCount(MaximumIterationsCount);
            hillClimbing.Evaluate();
            SetInitialValue(hillClimbing.Result);
            return hillClimbing.RealPrecision;
        }

        /// <summary>
        /// Создает случайную популяцию
        /// </summary>
        public override void CreateRandomPopulation()
        {
            if (_initialRange != null)
                DoGeneticAlgorithm();
            DoSimplexAlgorithm();
        }

        /// <summary>
        /// Выполняет поиск с использованием генетического алгоритма
        /// </summary>
        private void DoGeneticAlgorithm()
        {
            VectorChromosomeController manager = new VectorChromosomeController();
            manager.SetRange(_initialRange);
            manager.SetOrigin(GetResult());
            VectorGeneticAlgorithm finder = new VectorGeneticAlgorithm(Function, PointsFactory, manager);
            finder.Evaluate();
            SetInitialValue(finder.Result);
        }

        /// <summary>
        /// Выполняет поиск с использованием симплекс-метода
        /// </summary>
        private void DoSimplexAlgorithm()
        {
            SimplexAlgorithm finder = new SimplexAlgorithm(Function, PointsFactory, GetResult());
            finder.SetDesiredPrecision(Math.Sqrt(DesiredPrecision));
            finder.SetMaximumIterationsCount(MaximumIterationsCount);
            finder.Evaluate();
            SetInitialValue(finder.Result);
        }

        /// <summary>
        /// Возвращает/устанавливает начало гиперкуба домена функций
        /// </summary>
        public double[] Origin
        {
            get
            {
                return GetResult();
            }
            set 
            {
                SetInitialValue(value);
            }
        }

        /// <summary>
        /// Возвращает/устанавливает длины граней гиперкуба домена функций
        /// </summary>
        public double[] Range
        {
            get
            {
                return _initialRange;
            }
            set 
            { 
                _initialRange = value; 
            }
        }
    }
}
